import { Col } from "../../../../core/data_ext";
import { Library } from "../../../../core/library";
import SerializeAble, { Serialize, SerializeClass } from "../../../../core/serialize";
import { Subject } from "../../../../core/subject";
import { UniqueObjectConfig } from "../../../../core/unique_class";
import { KEvent, KEventConfig } from "./k_event";
import { KSelection } from "./k_selection";

export class KarmaRunFunction {
    method = "";
    args: any[] = [];
};

//事件执行历史。
@SerializeClass("KarmaRunEventDetail")
export class KarmaRunEventDetail extends SerializeAble {
    @Serialize()
    evtKey = "";
    @Serialize()
    selectInd = -1; //默认，没有选项。
    @Serialize()
    name = "";
    @Serialize()
    desc = "";


    evtUUid = "";
};

@SerializeClass("KarmaRun")
export class KarmaRun extends SerializeAble {
    subject = new Subject();
    @Serialize()
    eventRunCountCol: Col<KarmaRunEventDetail[]> = {};
    @Serialize()
    varCol: Col<number> = {};
    @Serialize()
    nextEvtKey = "";

    @Serialize()
    curEvtKey = "";
    curKEvt: KEvent = null;

    getEventRunCount(kEvt: KEvent) {
        if (!this.eventRunCountCol[kEvt.configKey]) {
            this.eventRunCountCol[kEvt.configKey] = [];
        }
        return this.eventRunCountCol[kEvt.configKey].length;
    }
    getLastEventRunDetail(kEvt: KEvent) {
        if (!this.eventRunCountCol[kEvt.configKey]) {
            this.eventRunCountCol[kEvt.configKey] = [];
        }
        return this.eventRunCountCol[kEvt.configKey][this.eventRunCountCol[kEvt.configKey].length - 1];
    }
    openEvent(kEvt: KEvent) {
        if (!this.eventRunCountCol[kEvt.configKey]) {
            this.eventRunCountCol[kEvt.configKey] = [];
        }
        let detail = new KarmaRunEventDetail();
        detail.evtUUid = kEvt.uuid;

        detail.evtKey = kEvt.configKey;
        detail.name = kEvt.data.name;
        detail.desc = kEvt.data.desc;
        this.eventRunCountCol[kEvt.configKey].push(detail);

        this.curEvtKey = kEvt.configKey;
        this.curKEvt = kEvt;

        this.subject.emit("open-event", kEvt);
    }
    closeEvent() {
        if (!this.curKEvt) {
            console.error("KarmaRun::runEvent, error: curKEvt为空");
            return;
        }
        if (this.curKEvt.data.funcs.length > 0) {
            this.curKEvt.data.funcs.forEach(funcStr => {
                this.runFunc(funcStr);
            });
        }
        this.subject.emit("close-event",this.getLastEventRunDetail(this.curKEvt));
    }
    openNextEvent() {
        if (!this.nextEvtKey) {
            console.error("KarmaRun::runNextEvent, error: nextEvtKey为空");
            return;
        }
        const kEvtConf = Library.GetRecord(KEventConfig, this.nextEvtKey);
        if (!kEvtConf) {
            console.error(`KarmaRun::runNextEvent, error: 没有找到 ${this.nextEvtKey} 事件`);
            return;
        }
        this.nextEvtKey = "";
        let kEvt = new KEvent();
        UniqueObjectConfig.AssignUniqueObject(kEvt, kEvtConf);
        this.openEvent(kEvt);
    }
    runSelection(kSel: KSelection) {
        if (kSel.data.funcs.length > 0) {
            kSel.data.funcs.forEach(funcStr => {
                this.runFunc(funcStr);
            });
        }
        let detail = this.getLastEventRunDetail(this.curKEvt);
        let ind = this.curKEvt.selections.findIndex(ele => ele == kSel);
        detail.selectInd = ind;
        if (kSel.data.desc) {
            detail.desc = kSel.data.desc;
        }
        this.subject.emit("run-selection", kSel);

        this.closeEvent();
    }

    runFunc(funcStr: string) {
        let tokens = this._parseToken(funcStr);
        console.log("RunFunc:", tokens);
        let krf = new KarmaRunFunction();
        krf.method = tokens[0];
        let originArgs = tokens.slice(2, tokens.length - 1);
        originArgs.forEach(str => {
            if (str == ",") {
                return;
            }
            switch (true) {
                case str[0] === "\'":
                case str[0] === "\"":
                case str[0] === "\`":
                    str = str.substring(1, str.length - 1);
                    break;
            }
            krf.args.push(str);
        })


        if (!this[`func_${krf.method}`]) {
            console.error(`KarmaRun::runFunc, error: 找不到方法(func_${krf.method})`);
            return;
        }
        this[`func_${krf.method}`](...krf.args);
        this.subject.emit("run-func", krf);

    }
    protected _parseToken(funcStr: string) {
        let seek = 0;
        let tokens: string[] = [];

        const isEnd = () => {
            return seek >= funcStr.length;
        }
        const peek = (offset = 0) => {
            if (seek + offset >= funcStr.length) {
                return "";
            }
            return funcStr[seek + offset];
        }
        const read = (len: number) => {
            let str = funcStr.substring(seek, seek + len);
            seek += len;
            return str;
        }
        const readUntil = (char: string = "", includeChar = true) => {
            let str = "";
            if (!char) {
                str = funcStr.substring(seek)
                seek = funcStr.length;
            }
            else {
                while (funcStr[seek] !== char && seek < funcStr.length) {
                    str += funcStr[seek++];
                }

                //"]"
                if (!isEnd()) {
                    if (includeChar) {
                        str += funcStr[seek++];
                    }
                    else {
                        seek++;
                    }
                }
            }
            return str;
        }

        while (!isEnd()) {
            let char = peek();
            switch (true) {
                case /^[_a-zA-Z\u4e00-\u9fa5]$/.test(char): //英文 或 下划线
                    {
                        let ind = 1;
                        while (/^[_0-9a-zA-Z\u4e00-\u9fa5]$/.test(peek(ind))) {
                            ind++;
                        }
                        let word = read(ind);
                        tokens.push(word);
                    }
                    break;
                case char === "(":
                case char === ")":
                    {
                        let str = read(1);
                        tokens.push(str);
                    }
                    break;
                case char === ",":
                    {
                        let str = read(1);
                        tokens.push(str);
                    }
                    break;
                case char === "\"": //字符串值
                case char === "\'": //字符串值
                case char === "\`": //字符串值
                    {
                        let char0 = read(1);
                        let str = char0 + readUntil(char);
                        tokens.push(str);
                    }
                    break;
                case /[0-9]/.test(char): //只有数字和 . 
                    let ind = 1;
                    while (/[0-9\.]/.test(peek(ind))) {
                        ind++;
                    }
                    if (peek(ind - 1) === ".") {
                        ind--;
                    }
                    let str = read(ind);
                    tokens.push(str);
                    break;
                case char === " ":
                case char === "\r":
                case char === "\n":
                    read(1);
                    break;
            }
        }

        return tokens;
    }
    func_var(key: string, value: any) {
        this.varCol[key] = value;
    }
    func_jump(key: string) {
        this.nextEvtKey = key;
    }
    func_mission(key: string) {
        this.subject.emit("mission", key);
    }
    func_job(key: string) {
        this.subject.emit("job", key);
    }
    func_ready(key: string) {
        this.subject.emit("ready", key);
    }
};